# -*- coding: utf-8 -*-
# @Time    : 2021/3/16 14:58
# @Author  : huangwei
# @File    : table_method.py
# @Software: PyCharm
import cv2
import numpy as np
from PIL import Image


def resize_img( img, size ):
    """ 将图片映射到SIZE大小的图片上并对周围进行填充，然后作为模型的输入 """
    # 修改 img 尺寸使其有一边与 size 相等
    w, h = size
    img_w, img_h = img.size
    ratio = min(w / img_w, h / img_h)

    new_w = int(img_w * ratio)
    new_h = int(img_h * ratio)

    new_img = img.resize((new_w, new_h), Image.BICUBIC)

    # 分别为长、宽变化的比例
    fx = new_w / img_w
    fy = new_h / img_h

    # 长宽剩下部分的一半的长度，用于将图片放置到中间四周进行填充
    dx = (w - new_w) // 2
    dy = (h - new_h) // 2

    # 对四周进行填充
    boxed_img = Image.new('RGB', size, (128, 128, 128))
    boxed_img.paste(new_img, (dx, dy))

    return boxed_img, fx, fy, dx, dy


def exp( x ):
    # 将 数组中小于-6的值变为-6，大于6的值变为6
    x = np.clip(x, -6, 6)
    y = 1 / (1 + np.exp(-x))
    return y


def sort_box( box ):
    # 将四个点按左上、右上、右下、左下排序输出
    x1, y1, x2, y2, x3, y3, x4, y4 = box[:8]
    pts = (x1, y1), (x2, y2), (x3, y3), (x4, y4)
    pts = np.array(pts, dtype="float32")

    # 先按 x 坐标大小进行排序，即从左到右进行排序
    x_sorted = pts[np.argsort(pts[:, 0]), :]
    # 对最左边两个点进行上下排序，分出左上角和左下角
    left_points = x_sorted[:2, :]
    right_points = x_sorted[2:, :]

    left_sort = left_points[np.argsort(left_points[:, 1]), :]
    left_top, left_down = left_sort

    # 同理可分出右上和右下
    right_sort = right_points[np.argsort(right_points[:, 1]), :]
    right_top, right_down = right_sort

    (x1, y1), (x2, y2), (x3, y3), (x4, y4) = np.array([left_top, right_top, right_down, left_down], dtype="float32")

    return x1, y1, x2, y2, x3, y3, x4, y4


def get_line( coords ):
    """
    返回该点集的最小外接矩形的与较长边平行的中心线
    :param coords:
    :return:
    """
    rect = cv2.minAreaRect(coords[:, ::-1])
    box = cv2.boxPoints(rect)
    box = box.reshape((8,)).tolist()

    # 将外接矩形四个点进行排序确定每一个点的位置
    box = sort_box(box)
    x1, y1, x2, y2, x3, y3, x4, y4 = box

    # 计算出矩形的长宽
    w = (np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) + np.sqrt((x3 - x4) ** 2 + (y3 - y4) ** 2)) / 2
    h = (np.sqrt((x2 - x3) ** 2 + (y2 - y3) ** 2) + np.sqrt((x1 - x4) ** 2 + (y1 - y4) ** 2)) / 2

    if w < h:
        xmin = (x1 + x2) / 2
        xmax = (x3 + x4) / 2
        ymin = (y1 + y2) / 2
        ymax = (y3 + y4) / 2

    else:
        xmin = (x1 + x4) / 2
        xmax = (x2 + x3) / 2
        ymin = (y1 + y4) / 2
        ymax = (y2 + y3) / 2

    return [xmin, ymin, xmax, ymax]


def draw_lines( img, lines, color=(0, 0, 0), line_width=3 ):
    tmp = np.copy(img)

    for line in lines:
        x1, y1, x2, y2 = line
        cv2.line(tmp, (int(x1), int(y1)), (int(x2), int(y2)), color, line_width, lineType=cv2.LINE_AA)

    return tmp


def dist( p1, p2 ):
    """ 两个点之间的距离 """
    return np.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)


def get_equation( p1, p2 ):
    """ 得到线段所在直线方程的一般式参数 """
    x1, y1 = p1
    x2, y2 = p2
    A = y2 - y1
    B = x1 - x2
    C = x2 * y1 - x1 * y2
    return A, B, C


def point_line( p, A, B, C ):
    """ 将点坐标带入直线方程的一般式中来判断点和线之间的关系 """
    x, y = p
    r = A * x + B * y + C
    return r


def line_line( line1, line2, alpha=10 ):
    """ 计算两条线段之间的距离，如果存在两条线段延申的交点小于一个范围则连接 """
    x1, y1, x2, y2 = line1
    ox1, oy1, ox2, oy2 = line2
    A1, B1, C1 = get_equation((x1, y1), (x2, y2))
    A2, B2, C2 = get_equation((ox1, oy1), (ox2, oy2))
    flag1 = point_line([x1, y1], A2, B2, C2)
    flag2 = point_line([x2, y2], A2, B2, C2)

    # 如果两条线段不相交
    if (flag1 > 0 and flag2 > 0) or (flag1 < 0 and flag2 < 0):
        # 两条线段延长线的交点
        x = (B1 * C2 - B2 * C1) / (A1 * B2 - A2 * B1)
        y = (A2 * C1 - A1 * C2) / (A1 * B2 - A2 * B1)
        p = (x, y)
        r0 = dist(p, (x1, y1))
        r1 = dist(p, (x2, y2))

        if min(r0, r1) < alpha:
            if r0 < r1:
                line1 = [p[0], p[1], x2, y2]
            else:
                line1 = [x1, y1, p[0], p[1]]

    return line1


def minAreaRectBox( coords ):
    """ 连通区域的外接矩形 """
    rect = cv2.minAreaRect(coords[:, ::-1])
    box = cv2.boxPoints(rect)
    box = box.reshape((8,)).tolist()
    box = sort_box(box)
    return box
